package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.feign.list.SkuEsFeignClient;
import com.atguigu.gmall.model.list.Goods;
import com.atguigu.gmall.model.product.SkuAttrValue;
import com.atguigu.gmall.model.product.SkuImage;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.model.product.SkuSaleAttrValue;
import com.atguigu.gmall.product.service.SkuAttrValueService;
import com.atguigu.gmall.product.service.SkuImageService;
import com.atguigu.gmall.product.service.SkuSaleAttrValueService;
import com.atguigu.starter.cache.core.DbCacheConsensusService;
import com.atguigu.starter.redisson.properties.BloomFilterProperties;
import com.atguigu.starter.redisson.properties.BloomProperty;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.gmall.product.service.SkuInfoService;
import com.atguigu.gmall.product.mapper.SkuInfoMapper;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author 钟涛
* @description 针对表【sku_info(库存单元表)】的数据库操作Service实现
* @createDate 2021-12-08 18:36:46
*/
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo>
    implements SkuInfoService{
    @Autowired
    private SkuInfoMapper skuInfoMapper;
    @Autowired
    private SkuImageService skuImageService;
    @Autowired
    private SkuAttrValueService skuAttrValueService;
    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Qualifier("skuBloomFilte")
    @Autowired
    private RBloomFilter<Object> rBloomFilter;

    @Autowired
    private BloomFilterProperties bloomFilterProperties;
    @Autowired
    private RedissonClient redissonClient;  //分布式锁操作类

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SkuEsFeignClient skuEsFeignClient;

    @Autowired
    private DbCacheConsensusService dbCacheConsensusService;

    @Override
    public void saveSkuInfo(SkuInfo skuInfo) {
        int insert = skuInfoMapper.insert(skuInfo);
        //获取sku的自增id
        Long id = skuInfo.getId();
        //缺sku_id
        List<SkuImage> imageList = skuInfo.getSkuImageList().stream().map((ele) -> {
            ele.setSkuId(id);
            return ele;
        }).collect(Collectors.toList());

        skuImageService.saveBatch(imageList);

        //缺sku_id
        List<SkuAttrValue> skuAttrValueList = skuInfo.getSkuAttrValueList().stream().map((ele) -> {
            ele.setSkuId(id);
            return ele;
        }).collect(Collectors.toList());
        skuAttrValueService.saveBatch(skuAttrValueList);

        //缺sku_id,spu_id
        List<SkuSaleAttrValue> skuSaleAttrValueList = skuInfo.getSkuSaleAttrValueList().stream().map((ele) -> {
            ele.setSkuId(id);
            ele.setSpuId(skuInfo.getSpuId());
            return ele;
        }).collect(Collectors.toList());
        skuSaleAttrValueService.saveBatch(skuSaleAttrValueList);
    }

    /**
     * 更新上下线状态
     * @param skuId
     * @param status
     */
    @Transactional
    @Override
    public void updateSkuOnSale(Long skuId, int status) {
        skuInfoMapper.updateSkuOnSale(skuId,status);
        //双删除缓存
        dbCacheConsensusService.delayDoubleDelete(RedisConst.SKUKEY_PREFIX+skuId);

        //es进行上下架操作，通过openFeign调用service-list服务
        if(status == 1){
            //上架
            Goods goods = skuInfoMapper.getSkuInfo2Goods(skuId);
            skuEsFeignClient.upSkuInfo(goods);
        }else{
            //下架
            skuEsFeignClient.downSkuInfo(skuId);
        }
    }

    /**
     * 只获取sku的价格
     * @param skuId
     * @return
     */
    @Override
    public BigDecimal getSkuPrice(Long skuId) {
        BigDecimal price = skuInfoMapper.getPrice(skuId);
        return price;
    }

    /**
     * 每隔三天自动重建布隆
     */
    @Scheduled(cron = "0 0 4 */3 * ?")
    @Override
    public void rebuildSkuBloomFilter() {
        //1 微服务实例众多，倒是，定时任务再各个机器同时启动
        //2.加分布式锁
        String lockKey = RedisConst.LOCK_PREFIX + RedisConst.BLOOM_REBUILD_LOCK;
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        try {
            //判断干活标志位
            String s = redisTemplate.opsForValue().get(RedisConst.BLOOM_REBUILD_STATUS);
            if ("1".equals(s)) {
                //别人已经干完了
                return;
            }
            //定期重建
            rBloomFilter.delete();
            BloomProperty skuBloomProperty = bloomFilterProperties.getConfig().get("sku");

            rBloomFilter.tryInit(skuBloomProperty.getInsertions(), skuBloomProperty.getFalseProbability());
            //同步数据
            List<Long> skuIds = skuInfoMapper.selectAllSkuIds();
            for (Long skuId : skuIds) {
                //把商品id添加到布隆过滤器中,id转成String类型
                rBloomFilter.add(skuId.toString());
            }
            //这个标志位只存在一天,当天一定会有人干成功
            redisTemplate.opsForValue().set(RedisConst.BLOOM_REBUILD_STATUS, "1", 1, TimeUnit.DAYS);
        } finally {
            lock.unlock();
        }
    }
}




